#!/bin/bash
# vim:tabstop=2 shiftwidth=2 smarttab expandtab softtabstop=2 autoindent

displayUsage () {
    echo "Purpose:  Encode a video using the x264 codec and the matroska (mkv) file format." >&2
    echo "          If a file with the same name ending in .chp is found, it is assumed" >&2
    echo "          to be a chapter file and will be bundled into the mkv file." >&2
    echo "Usage:    $NAME [-options] inputfile" >&2
    echo "Options:  -m stream : Manually specify audio and/or video streams for encoding." >&2
    echo "          -c cropinfo : Manually specify crop info instead of autodetect." >&2
    echo "                        Use \"-c NO\" to prevent cropping." >&2
    echo "          -s starttime : Specify the start time within the video to start encoding." >&2
    echo "          -l length : Specify the length or duration to encode." >&2
    echo "          -i : Deinterlace video as part of encoding process." >&2
    echo "Example:  $NAME videos/example/movie1.vob" >&2
    echo "          Would encode \"movie1-x264.mkv\" in videos/example/" >&2
    echo "          $NAME -s 00:05:00 -l 00:00:10 videos/example/movie1.vob" >&2
    echo "          Would encode the same movie but would skip 5 minutes and then encode 10 seconds." >&2
    echo "          $NAME -m 0:1 -m 0:3 videos/example/movie1.vob" >&2
    echo "          Would encode streams 1 and 3.  Use ffmpeg -i movie1.vob to view available streams." >&2
    echo "Note:     This script can be safely executed in parallel on a number of video files." >&2
    echo "          A file will be skipped if it is already being encoded by another parallel" >&2
    echo "          copy of this script.  The following code for example can be used:" >&2
    echo "          find . -name *.vob -exec ${NAME} '{}' ';' & #invocation #1" >&2
    echo "          find . -name *.vob -exec ${NAME} '{}' ';' & #invocation #2" >&2
    echo "          The first invocation will grab the first file and start encoding, the second" >&2
    echo "          invocation will note that the first file is already being encoded and will skip" >&2
    echo "          to the second file.  The two will alternate until all files have been encoded." >&2
}

NO_ARGS=1
E_OPTERROR=65
E_EXECUTION_ERROR=1
NAME=${0##*/}
CROP='AUTO'
DEINTERLACE=''
STREAMS=''
START=''
LENGTH=''

# Test that required commands are in the path
for CMD in video-cropdetect ffmpeg mkvmerge; do
   type $CMD &> /dev/null
   if [ $? != "0" ]; then
      echo "The command '$CMD' is required and is not in your path" >&2
      exit $E_EXECUTION_ERROR
   fi
done

while getopts ":m:c:s:l:i" Option
do
    case $Option in
	m) STREAMS="${STREAMS}-map $OPTARG ";;
	c) CROP=$OPTARG;;
	s) START="-ss $OPTARG";;
	l) LENGTH="-t $OPTARG";;
	i) DEINTERLACE='-filter:v yadif';;
	*) echo "Error: unknown option -$OPTARG" >&2
	   displayUsage
	   exit $E_OPTERROR;;
    esac
done

shift $(($OPTIND - 1))

if [[ $# < "$NO_ARGS" ]]
then
    displayUsage
    exit $E_OPTERROR
fi

INPUTFILE=$1

if [[ ! -e "$INPUTFILE" ]]
then
    echo "Error: Input file \"$INPUTFILE\" does not exist" >&2
    exit $E_OPTERROR
fi

for EXT in dv ps PS vob VOB vro VRO avi AVI mkv MKV
do
    if [[ "${INPUTFILE%.${EXT}}" != "${INPUTFILE}" ]]
    then
	BASENAME=${INPUTFILE%.${EXT}}
    fi
done

if [[ "${BASENAME}" == "" ]]
then
    echo "Unrecognized input file format"
    exit $E_OPTERROR
fi

OUTFILE="${BASENAME}-x264.mkv"
CHPFILE="${BASENAME}.chp"

if [[ -e "${OUTFILE}" ]]
then
    echo "Output file ${FILE} exists."
    exit $E_EXECUTION_ERROR
fi

LOCKFILE="${BASENAME}.lock"
if [[ -e "${LOCKFILE}" ]]
then
	echo "Video file already being encoded.  Remove \"${LOCKFILE}\" if you are confident this is not the case."
	exit 0
fi

touch "${LOCKFILE}"

if [[ "$CROP" == 'AUTO' ]]
then
    echo "Detecting crop areas at borders... Please wait"
    CROP=$(video-cropdetect "${INPUTFILE}")
    CROP="-vf crop=$CROP"
    if [ $? != "0" ]; then exit $E_EXECUTION_ERROR; fi
    echo "Crop detection completed"
elif [[ "$CROP" == 'NO' ]]
then
    CROP=''
else
    CROP="-vf crop=$CROP"
fi

nice -n 19 ffmpeg ${DEINTERLACE} -i "${INPUTFILE}" ${STREAMS} ${START} ${LENGTH} -sn -acodec copy -vcodec libx264 -preset veryslow -crf 18 $CROP "${OUTFILE}"

ECODE=$?

if [ $ECODE != "0" ]; then exit $E_EXECUTION_ERROR; fi

if [[ -e "$CHPFILE" ]]
then
	TEMPFILE="${BASENAME}-tmp.mkv"
	mkvmerge -o "$TEMPFILE" --chapters "$CHPFILE" "$OUTFILE"
	if [ $? != "0" ]; then exit $E_EXECUTION_ERROR; fi
	if [[ -e "$TEMPFILE" ]]
	then
		rm "${OUTFILE}"
		mv "${TEMPFILE}" "${OUTFILE}"
	fi
fi

rm "${LOCKFILE}"
